package it.polimi.dei.SeCo.YAGO;

import it.polimi.dei.SeCo.Main;
import it.polimi.dei.SeCo.GeoNames.GeoNamesTool;

import java.util.List;

import org.geonames.Toponym;

/**
 * @author Simone Benefico
 */
public class GeoEntity {
	private String name;
	private String geoType;
	private String geoNamesId;
	private String location;
	private Double latitude;
	private Double longitude;
	
	/**
	 * Creates an instance of GeoEntity, assigns the parameters to the Class variables and fills the empty ones using completeEntity().
	 * @param name name of the geographical entity (location)
	 * @param geoType type of the GeoEntity from YAGO2 or featureClass from GeoNames
	 * @param geoNamesId GeoNamesId from fact "hasGeoNamesId" in YAGO2 or from GeoNames
	 * @param location location where the GeoEntity is located in from the fact "isLocatedIn" in YAGO2 or from the hierarchy in GeoNames
	 * @param latitude latitude of the GeoEntity
	 * @param longitude longitude of the GeoEntity
	 * @see #completeEntity()
	 */
	public GeoEntity(String name, String geoType, String geoNamesId, String location, Double latitude, Double longitude) {
		this.name = name;
		this.geoType = geoType;
		this.geoNamesId = geoNamesId;
		this.location = location;
		this.latitude = latitude;
		this.longitude = longitude;
		if(geoType==null || geoType.equals("yagoGeoEntity") || location==null || location.isEmpty() || latitude==null || longitude==null)
			completeEntity();
	}
	
	/**
	 * Uses information from GeoNames to complete the GeoEntity by filling the empty variables.<br>
	 * In order to get the right Toponym from GeoNames, the method analyze: geoNamesId, coordinates (both latitude and longitude) and the location where the GeoEntity is located in; at least one of them must be equal to the corresponding variable from YAGO2. 
	 */
	private void completeEntity() {
		Toponym geoEntity = null;
		List<Toponym> toponyms = Main.gn.filterResults(Main.gn.search(name), name);
		if(toponyms!=null && !toponyms.isEmpty()) {
			if(geoNamesId!=null && !geoNamesId.isEmpty()) {
				for(Toponym toponym : toponyms) {
					if(toponym.getGeoNameId()==Integer.parseInt(geoNamesId)) {
						geoEntity = toponym;
						break;
					}
				}
			}
			else {
				if(latitude!=null && longitude!=null) {
					for(Toponym toponym : toponyms) {
						if((int)toponym.getLatitude()==latitude.intValue() && (int)toponym.getLongitude()==longitude.intValue()) {
							geoEntity = toponym;
							break;
						}
					}
				}
				else {
					if(location!=null) {
						for(Toponym toponym : toponyms) {
							List<String> hierarchy = Main.gn.hierarchyToString(toponym);
							if(hierarchy.contains(location)) {
								geoEntity = toponym;
								break;
							}								
						}
					}
					else
						if(toponyms.size()==1)
							geoEntity = toponyms.get(0);
				}
			}
			if(geoEntity!=null) {
				if(geoType==null)
					geoType = GeoNamesTool.featureCodeNames.get(geoEntity.getFeatureCode());
				if(location==null || location.isEmpty()) {
					List<Toponym> hierarchy = Main.gn.hierarchy(geoEntity);
					Toponym t = hierarchy.get(hierarchy.size()-2);
					location = t.getName()+"("+GeoNamesTool.featureCodeNames.get(t.getFeatureCode())+")";
				}
				if(latitude==null)
					latitude = geoEntity.getLatitude();
				if(longitude==null)
					longitude = geoEntity.getLongitude();
			}
			if(geoType==null)
				geoType = "yagoGeoEntity";
		}		
	}

	/**
	 * Creates an instance of GeoEntity and assigns the the name to it.
	 * @param name name of the geographical entity
	 */
	public GeoEntity(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getGeoType() {
		return geoType;
	}

	public void setGeoType(String geoType) {
		this.geoType = geoType;
	}

	public String getGeoNamesId() {
		return geoNamesId;
	}

	public void setGeoNamesId(String geoNamesId) {
		this.geoNamesId = geoNamesId;
	}

	public String getLocation() {
		return location;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	public double getLatitude() {
		return latitude;
	}

	public void setLatitude(double latitude) {
		this.latitude = latitude;
	}

	public double getLongitude() {
		return longitude;
	}

	public void setLongitude(double longitude) {
		this.longitude = longitude;
	}

	@Override
	public String toString() {
		String string = "GeoEntity [name=" + name;
		if(geoType!=null && !geoType.isEmpty())
			string+=", geoType=" + geoType;
		if(location!=null && !location.isEmpty())
			string+=", isLocatedIn=" + location;
		if(latitude!=null)
			string+=", latitude=" + latitude;
		if(longitude!=null)
			string+=", longitude=" + longitude;
		string+="]";
		return string;
	}
	
}
